-- Version: 0.1.0$
require "sprites"
require "theme"

graph = {
	-- Инициализация
	init = function ()
		graph.window = {
			w = theme.get 'scr.w';
			h = theme.get 'scr.h';
		}
	end;
	
	-- Фрейм
	frame = function (f, sw, sh)
		f.sw, f.sh = sw, sh
		
		if not f.fx then f.fx = 0 end
		if not f.fy then f.fy = 0 end
		if not f.fw then f.fw = f.sw end
		if not f.fh then f.fh = f.sh end
		
		-- TODO сделать бы еще смещение с тупиком
		-- TODO сделать циклическое смещение с копированием спрайта
		-- с циклическими и бесконечными координатами
		f.shift = function (x, y, loop)
			f.fx = f.fx + x
			f.fy = f.fy + y
			
			if loop then
				if f.fx >= f.sw then f.fx = 0 end
				if f.fy >= f.sh then f.fy = 0 end
			end
		end
		
		f.get_frame = function ()
			return f.fx, f.fy, f.fw, f.fh
		end
		
		f.set_frame = function (frame)
			if frame.fx then f.fx = frame.fx end
			if frame.fy then f.fy = frame.fy end
			if frame.fw then f.fw = frame.fw end
			if frame.fh then f.fh = frame.fh end
		end
		
		return f
	end;
	
	-- Класс обьекта
	-- Описывает вид и поведение спрайта
	object = function (o)
		-- Входящие параметы
		o.name = deref(o)
		
		if not o.spr then
			error('В конструктор обьекта не передан спрайт', 2)
		else
			o.spr = sprite.load (o.spr)
		end
		
		o.size = {}
		o.size.w, o.size.h = sprite.size (o.spr)
		
		if not o.frame then
			local w, h = sprite.size (o.spr)
			o.frame = graph.frame ({}, w, h)
		else
			local w, h = sprite.size (o.spr)
			o.frame = graph.frame (o.frame, w, h)
		end
		
		if not o.alpha then o.alpha = undef end
		
		-- Внутренние параметры
		o.rend_obj = sprite.load ('blank:10x10')
		o.animation = {}
		
		-- Методы
		o.get_name = function ()
			return o.name
		end
		
		o.get_sprite = function ()
			return o.rend_obj
		end
		
		o.get_frame = function ()
			return o.frame.get_frame()
		end
		
		o.set_frame = function (frame)
			o.frame.set_frame(frame)
		end
		
		o.render = function ()
			local fx, fy, fw, fh = o.frame.get_frame()
			sprite.free(o.rend_obj)
			o.rend_obj = sprite.load ('blank:'..fw..'x'..fh)
			sprite.copy (o.spr, fx, fy, fw, fh, o.rend_obj, 0, 0, o.alpha)
			return o.rend_obj
		end
		
		o.rend_obj = o.render()
		
		return o
	end;
	
	node = function (n)
		n.name = n.obj.get_name()
		
		if not n.coord then
			n.coord = {x = 0, y = 0}
		else
			if not n.coord.x then n.coord.x = 0 end
			if not n.coord.y then n.coord,y = 0 end
		end
		
		n.get_name = function ()
			return n.name
		end
		
		n.get_obj = function ()
			return n.obj
		end
		
		n.get_coord = function ()
			return n.coord.x, n.coord.y
		end
		
		n.set_coord = function (x, y)
			if x then n.coord.x = x end
			if y then n.coord.y = y end
			return n
		end
		
		return n
	end;
	
	scene = function (s)
		if not s.size then
			s.size = {w = graph.window.w, h = graph.window.h}
		else
			if not s.size.w then s.size.w = graph.window.w end
			if not s.size.h then s.size.h = graph.window.h end
		end
		
		if not s.frame then
			s.frame = graph.frame ({}, s.size.w, s.size.h)
		else
			s.frame = graph.frame (s.frame, s.size.w, s.size.h)
		end
		
		if not s.alpha then s.alpha = undef end
		
		s.rend_scn = sprite.load ('box:'..s.size.w..'x'..s.size.h)
		s.nodes = {}
		
		s.get_sprite = function ()
			return s.rend_scn
		end
		
		s.add_obj = function (obj, coord)
			if not obj then error('В функцию не передан объект', 2) end
			
			local node = graph.node {obj = obj, coord = coord}
			table.insert(s.nodes, node)
			return s
		end
		
		s.get_node = function (obj)
			local i
			for i = 1, #s.nodes, 1 do
				if s.nodes[i].get_name() == obj.name then return s.nodes[i] end
			end
			error('Нода не найдена', 2)
		end
		
		-- рендер спрайта сцены
		-- TODO добавить фреймы
		-- (надеюсь эта ф-ия еще понадобится)
		s.render = function ()
			local i
			sprite.free(s.rend_scn)
			s.rend_scn = sprite.load ('box:'..s.size.w..'x'..s.size.h)
			for i = 1, #s.nodes, 1 do
				local x, y = s.nodes[i].get_coord()
				sprite.draw (s.nodes[i].get_obj().get_sprite(), s.rend_scn, x, y)
			end
			return s.rend_scn
		end
		
		-- NOTE хак
		-- Из-за того, что нельзя нормально создать пустой спрайт
		-- приходится рисовать как фон спрайта - спрайт экрана
		-- и рисовать сцену этим методом
		-- рисование сцены как спрайта
		s.hack_draw = function (x, y)
			if not x then x = 0 end
			if not y then y = 0 end
			local i
			local fx, fy, fw, fh = s.frame.get_frame()
			sprite.free(s.rend_scn)
			s.rend_scn = sprite.load ('box:'..s.size.w..'x'..s.size.h)
			sprite.draw (sprite.screen(), s.rend_scn, -x, -y)
			for i = 1, #s.nodes, 1 do
				local nx, ny = s.nodes[i].get_coord()
				sprite.draw (s.nodes[i].get_obj().get_sprite(), s.rend_scn, nx, ny)
			end
			sprite.draw (s.rend_scn, fx, fy, fw, fh, sprite.screen(), x, y, s.alpha)
		end
		
		-- Рисование сцены как логики
		s.draw = function (x, y)
			if not x then x = 0 end
			if not y then y = 0 end
			local i
			for i = 1, #s.nodes, 1 do
				local nx, ny = s.nodes[i].get_coord()
				local fx, fy, fw, fh = s.frame.get_frame()
				sprite.draw (s.nodes[i].get_obj().get_sprite(), fx-nx, fy-ny, fw, fh,sprite.screen(), x, y)
			end
		end
		
		-- NOTE не обязательный рендер в сцене
		-- (если только ноды не будут кидаться в конструктор)
		-- но по идее сцену и объект объеденить бы
		s.rend_scn = s.render()
		
		return s
	end;
}
